﻿Imports System.IO, System.Reflection, System.Windows.Forms, EnvDTE


''' <summary>
''' Stores A List of All Loaded Assemblies. 
''' 
''' Try Simplifying this my making it A Shared Singleton 
''' </summary>
''' <remarks></remarks>
''' <features></features>
''' <stepthrough></stepthrough>
Public Class ReferenceResolver

    ''' <summary>
    ''' The Assembly of the Project Currently being Debugged
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    Public Property RootAssembly As Assembly
    Private Shared m_loadedAssemblies As New Dictionary(Of String, Assembly)

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="rootAssemblyPath">The Assembly of the Project Currently being Debugged</param>
    ''' <remarks></remarks>
    ''' <stepthrough>Enabled</stepthrough>
    Public Sub New(ByVal rootAssemblyPath As String)
        If m_loadedAssemblies.ContainsKey(rootAssemblyPath) Then
            RootAssembly = m_loadedAssemblies(rootAssemblyPath)
        Else
            Dim path__1 As String = TempFileNameService.GetNewFileName(Path.GetExtension(rootAssemblyPath))
            File.Copy(rootAssemblyPath, path__1, True)
            RootAssembly = Assembly.LoadFile(path__1)
            m_loadedAssemblies.Add(rootAssemblyPath, RootAssembly)
        End If
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="rootAssembly__1"></param>
    ''' <remarks></remarks>
    ''' <stepthrough>Enabled</stepthrough>
    <DebuggerStepThrough()>
    Public Sub New(ByVal rootAssembly__1 As Assembly)
        RootAssembly = rootAssembly__1
    End Sub






    Private Shared m_referenceLists As New Dictionary(Of Assembly, List(Of Assembly))()

    ''' <summary>
    ''' Returns All the Assemblies(As List(Of Assembly)) Used in the <see cref="Mod_Utilities.DTE">DTE's Debugger</see>
    ''' </summary>
    ''' <value></value>
    ''' <remarks></remarks>
    Public ReadOnly Property ReferencedAssemblies() As List(Of Assembly)
        Get
            If Not m_referenceLists.ContainsKey(RootAssembly) Then
                Dim allAssemblies As New List(Of Assembly)()
                For Each process In Mod_Utilities.DTE.Debugger.DebuggedProcesses.Cast(Of Process)()
                    Try
                        Dim exceptionCount As Integer = Integer.MaxValue - 1
                        Dim lastExceptionCount As Integer = Integer.MaxValue
                        While exceptionCount < lastExceptionCount
                            lastExceptionCount = exceptionCount
                            exceptionCount = 0
                            For Each [module] In Diagnostics.Process.GetProcessById(process.ProcessID).Modules.Cast(Of Diagnostics.ProcessModule)()
                                Try
                                    allAssemblies.Add(Assembly.LoadFile([module].FileName))
                                Catch exc As Exception
                                    If TypeOf exc Is BadImageFormatException Then
                                        Diagnostics.Debug.WriteLine(" -> " & Convert.ToString([module].ModuleName) & " is propably a unmanaged file")
                                    End If
                                    exceptionCount += 1
                                End Try
                            Next
                        End While
                    Catch harglgargl As Exception
                        MessageBox.Show(harglgargl.ToString())
                    End Try
                Next

                Dim paths As List(Of String) = allAssemblies.Select(Of String)(Function(x) Path.GetDirectoryName(x.Location)).ToList
                Dim assemblies As New List(Of Assembly)()
                For Each assembly__1 In allAssemblies
                    Dim subAssemblies = RootAssembly.GetRecursive(New List(Of Assembly), Function(a, list) a.GetReferencedAssemblies.Select(Function(an) TryToLoadAssembly(paths, an)).Where(Function(ass) Not list.Contains(ass)))
                    assemblies.AddRange(subAssemblies)
                Next
                assemblies.Add(RootAssembly)
                m_referenceLists.Add(RootAssembly, assemblies.Where(Function(a) a IsNot Nothing).Distinct().ToList())
            End If
            Return m_referenceLists(RootAssembly)
        End Get
    End Property

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="paths"></param>
    ''' <param name="assemblyName"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    ''' <stepthrough>Enable ASAP</stepthrough>
    Private Function TryToLoadAssembly(ByVal paths As List(Of String), ByVal assemblyName As AssemblyName) As Assembly
        Dim ass As Assembly = Nothing
        Try
            ass = Assembly.Load(assemblyName)
        Catch
            For Each path__1 As String In paths
                Try
                    Dim file As String = Path.Combine(path__1, assemblyName.Name & ".dll")
                    ass = Assembly.LoadFile(file)
                Catch
                End Try
            Next
        End Try
        Return ass
    End Function

End Class